/* 
 *  Copyright 2012 CodeMagi, Inc.
 * 
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.codemagi.servlets.search;

import com.codemagi.login.AccessException;
import com.codemagi.login.LoginException;
import com.codemagi.servlets.AppException;
import com.codemagi.servlets.search.beans.*;
import com.codemagi.util.*;
import java.io.*;
import javax.servlet.http.*;
import javax.xml.transform.*;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.*;
import org.apache.fop.apps.Driver;
import org.apache.fop.apps.Options;
import org.apache.log4j.*;
import org.exolab.castor.mapping.*;
import org.exolab.castor.xml.*;

/**
 * The SearchControllerFOP class is a framework for creating customized searches. 
 * Extend this class to implement the <code>dispatchSearch</code> and 
 * <code>dispatchSort</code> methods for your specific database schema. Also 
 * extend the <code>SearchBean</code> class to include the specific fields 
 * you wish to search. 
 *
 *  @version 1.0
 *  @author August Detlefsen for CodeMagi, Inc.
 */
public abstract class SearchControllerFOP extends com.codemagi.servlets.search.SearchController {

    //set to true to view debug output
    Logger log = Logger.getLogger(this.getClass());

    //MEMBERS specific to SearchControllerFOP

    //VIEWS specific to SearchControllerFOP

    //MESSAGES specific to SearchControllerFOP 
    protected static final String MSG_NO_OBJECT      = "This page cannot be rendered without an object to output to PDF.";
    protected static final String MSG_NO_STYLE       = "This page cannot be rendered without a valid style sheet.";


    /**
     * Dispatches <code>pdf</code> actions. Returns result set as PDF output. 
     */
    protected String dispatchPdf(HttpServletRequest request, HttpServletResponse response, String xslFile, String userConfig) 
	throws LoginException, AccessException {

        log.debug("***** dispatchPdf *****");

        //next page if operation is successful                                                                            
        String nextPage = VIEW_RESULTS;

	try {
	    //get session                                                                                                      
	    HttpSession session = request.getSession();

	    //get SearchBean from session                                                                                  
	    ISearchBean bean = (ISearchBean)session.getAttribute(beanName);
	    log.debug("Bean name is " + beanName + "\n");
	    
	    //check we have valid components to work with
	    if(bean == null) throw new AppException(MSG_NO_SEARCH);
	    if("".equals(xslFile)) throw new AppException(MSG_NO_STYLE);

	    //	    String query = bean.getQuery();
	    GridList displayObject = getResults(bean);

	    Options options = null;
	    
	    //userConfig allows per app config such as custom TTF use
	    if(userConfig != null) {
		File userConfigFile = new File(userConfig);
		options = new Options(userConfigFile);
		log.debug("userConfigFile: " + userConfigFile.getPath());
	    }


            //marshal and output

            String resultOutput = "search_results";

            log.debug("Marshalling display object to PDF...");

	    StringWriter writer = new StringWriter();
	    
	    Marshaller m = new Marshaller(writer);
	    m.setMapping(mapping);
	    m.setRootElement(resultOutput);
	    m.marshal(displayObject, writer);
	    
	    //first we need input sources
	    
	    //xmlSource = what we marshalled;
	    Reader xmlReader = new StringReader(writer.toString());
	    org.xml.sax.InputSource xmlSource = new org.xml.sax.InputSource(xmlReader);
	    
	    log.debug("xmlSource created from " + writer.toString());
	    
	    //xslSource = the style sheet file;
	    Source xslSource = new StreamSource(xslFile);
	    
	    log.debug("xslSource created from " + xslFile);
	    
	    ByteArrayOutputStream out = new ByteArrayOutputStream();
	    
	    response.setContentType("application/pdf");
	    
	    Driver driver = new Driver();
	    driver.setRenderer(Driver.RENDER_PDF);
	    driver.setOutputStream(out);
	    driver.setRenderer(Driver.RENDER_PDF);	    
	    log.debug("Driver created");
	    
	    
	    TransformerFactory factory = TransformerFactory.newInstance();
	    Transformer transformer = factory.newTransformer(xslSource);
	    
	    log.debug("factory and transformer ok");
	    
	    // Set the value of a <param> in the stylesheet
	    transformer.setParameter("versionParam", "2.0");
	    
	    // Setup input for XSLT transformation
	    Source src = new StreamSource(xmlReader);
	    
	    // Resulting SAX events (the generated FO) must be piped through to FOP
	    Result res = new SAXResult(driver.getContentHandler());
	    
	    log.debug("new SAXResult");
	    
	    // Start XSLT transformation and FOP processing
	    transformer.transform(src, res);
	    
	    log.debug("Driver ran");
	    
	    byte[] content = out.toByteArray();
	    response.setContentLength(content.length);
	    response.getOutputStream().write(content);
	    response.getOutputStream().flush();
	    
	    log.debug("response sent output");

	    org.apache.fop.configuration.Configuration config = new org.apache.fop.configuration.Configuration();
	    java.util.List fonts = config.getFonts();
	    log.debug("fonts: " + fonts.size());
	    
	    nextPage = VIEW_PDF;
	
	} catch (org.apache.fop.apps.FOPException fop) {
	    log.debug("", fop);
	    request.setAttribute("error_message", fop.getMessage());

	} catch (TransformerException tr) {
	    log.debug("", tr);
	    request.setAttribute("error_message", tr.getMessage());

	} catch (IOException io) {
	    log.debug("", io);
	    request.setAttribute("error_message", io.getMessage());

	} catch (XMLException xm) {
	    log.debug("", xm);
	    request.setAttribute("error_message", xm.getMessage());

	} catch (MappingException ma) {
	    log.debug("", ma);
	    request.setAttribute("error_message", ma.getMessage());

	} catch (AppException ae) {
	    log.debug("", ae);
	    request.setAttribute("error_message", ae.getMessage());
	}
	
        return nextPage;
    }
    


}
